//
//  TTWebSocketManager.m
//  PPDL
//
//  Created by 王洋 on 2019/8/17.
//  Copyright © 2019 王洋. All rights reserved.
//

#import "TTUDIDManager.h"
#import "TTWebSocketManager.h"
#import "AFNetworkReachabilityManager.h"

@interface TTWebSocketManager ()<SRWebSocketDelegate>

@property (nonatomic, strong) NSTimer *heartBeatTimer; //心跳定时器
@property (nonatomic, strong) NSTimer *netWorkTestingTimer; //没有网络的时候检测网络定时器
//@property (nonatomic, assign) NSTimeInterval reConnectTime; //重连时间
@property (nonatomic, strong) NSMutableArray *sendDataArray; //存储要发送给服务端的数据

@end

@implementation TTWebSocketManager

+ (instancetype)shared{
    static TTWebSocketManager *_instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc]init];
    });
    return _instance;
}

- (instancetype)init
{
    self = [super init];
    if(self){
//        self.reConnectTime = 0;
        self.isActivelyClose = NO;
        self.isFinish = NO;
        self.sendDataArray = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)refreshParam {
//    self.reConnectTime = 0;
    self.isActivelyClose = NO;
    self.isFinish = NO;
    self.connectType = WebSocketDefault;
}

#pragma mark --------------------------------------------------------建立长连接
- (void)connectServer {
//    self.isActivelyClose = NO;
    self.webSocket.delegate = nil;
    [self.webSocket close];
    _webSocket = nil;
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.wsUrl]];
    self.webSocket = [[SRWebSocket alloc] initWithURLRequest:request];
    self.webSocket.delegate = self;
    
//    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//    queue.maxConcurrentOperationCount = 1;//zc read:并发数为1==>串行队列
//    [self.webSocket setDelegateOperationQueue:queue];
    
    [self.webSocket open];
}

#pragma mark --------------------------------------------------------sendPing
- (void)sendPing:(id)sender{
    [self.webSocket sendPing:nil];
}

#pragma mark - socket delegate
#pragma mark --------------------------------------------------webSocketDidOpen
-(void)webSocketDidOpen:(SRWebSocket *)webSocket{
    
    if ([self.delegate respondsToSelector:@selector(webSocketDidConnectToServer)]) {
        [self.delegate webSocketDidConnectToServer];
    }
    
//    [SVProgressHUD dismiss];
    
    NSLog(@"socket 已连接");
    self.isConnect = YES;
    self.connectType = WebSocketConnect;
    [self initHeartBeat];///开始心跳
}

#pragma mark --------------------------------------------------- socket 连接失败
-(void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{
    
//    [SVProgressHUD dismissWithDelay:1];

    NSLog(@"连接失败");
    self.isConnect = NO;
    self.connectType = WebSocketDisconnect;
    
//    NSLog(@"连接失败，这里可以实现掉线自动重连，要注意以下几点");
//    NSLog(@"1.判断当前网络环境，如果断网了就不要连了，等待网络到来，在发起重连");
//    NSLog(@"3.连接次数限制，如果连接失败了，重试10次左右就可以了");
    
    //判断网络环境
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable){
        
        [self noNetWorkStartTestingTimer];// 没有网络  开启网络检测定时器
    }else{ //有网络
        
        [self reConnectServer];//连接失败就重连
    }
}

#pragma mark --------------------------------------------------- socket 接收消息
-(void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithString:(NSString *)string{
    
    NSLog(@"接收消息----  %@",string);
    if ([self.delegate respondsToSelector:@selector(webSocketManagerDidReceiveMessageWithString:)]) {
        [self.delegate webSocketManagerDidReceiveMessageWithString:string];
    }
}

#pragma mark --------------------------------------------------- socket 关闭连接
-(void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
    
//    [SVProgressHUD dismiss];

    self.isConnect = NO;
    if(self.isActivelyClose){
        self.connectType = WebSocketDefault;
        return;
    }else{
        self.connectType = WebSocketDisconnect;
    }
    
    NSLog(@"websocket连接关闭，断开连接时销毁心跳 code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
    
    [self destoryHeartBeat]; //断开连接时销毁心跳
    
    //判断网络环境
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable){ //没有网络
        NSLog(@"websocket开启网络检测");
        [self noNetWorkStartTestingTimer];//开启网络检测
    }else{ //有网络
        NSLog(@"关闭连接");
        _webSocket = nil;
        [self reConnectServer];//连接失败就重连
    }
}

#pragma mark --------------------------------------------------- socket ping
-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongData{
    NSLog(@"接受pong数据--> %@",pongData);
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    
    if ([self.delegate respondsToSelector:@selector(webSocketManagerDidReceiveMessageWithString:)]) {
        [self.delegate webSocketManagerDidReceiveMessageWithString:message];
    }    
}

#pragma mark - NSTimer

#pragma mark --------------------------------------------------- socket 初始化心跳
- (void)initHeartBeat{
    //心跳没有被关闭
    if(self.heartBeatTimer) {
        return;
    }
    [self destoryHeartBeat];
    dispatch_main_async_safe(^{
        self.heartBeatTimer  = [NSTimer timerWithTimeInterval:30 target:self selector:@selector(senderheartBeat) userInfo:nil repeats:true];
        [[NSRunLoop currentRunLoop]addTimer:self.heartBeatTimer forMode:NSRunLoopCommonModes];
    })
    
}
#pragma mark --------------------------------------------------- socket 重新连接
- (void)reConnectServer{
    
    if (self.isFinish || self.isActivelyClose || self.webSocket.readyState == SR_OPEN) {
        return;
    };

//    if(self.reConnectTime > 100){  //重连10次 2^10 = 1024
//        self.reConnectTime = 0;
//        return;
//    }
    
//    [SVProgressHUD showWithStatus:@"哎呀，人太多，正在尝试重新连接"];

    WEAKSELF
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        if(weakSelf.webSocket.readyState == SR_OPEN && weakSelf.webSocket.readyState == SR_CONNECTING) {
            return;
        }
        
        [weakSelf connectServer];
        
//        if(weakSelf.reConnectTime == 0){
//            weakSelf.reConnectTime = 2;
//        }else{
//            weakSelf.reConnectTime += 2;
//        }
    });
}

#pragma mark --------------------------------------------------- socket 发送心跳
- (void)senderheartBeat{
    //和服务端约定好发送什么作为心跳标识，尽可能的减小心跳包大小
    WEAKSELF
    dispatch_main_async_safe(^{
        if(weakSelf.webSocket.readyState == SR_OPEN){
            [weakSelf sendPing:nil];
        }
    });
}

#pragma mark --------------------------------------------------- socket 没有网络的时候 网络检测
- (void)noNetWorkStartTestingTimer{
    WEAKSELF
    dispatch_main_async_safe(^{
        weakSelf.netWorkTestingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(noNetWorkStartTesting) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:weakSelf.netWorkTestingTimer forMode:NSDefaultRunLoopMode];
    });
}
#pragma mark --------------------------------------------------- socket 定时检测网络
- (void)noNetWorkStartTesting{
    //有网络
    if(AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus != AFNetworkReachabilityStatusNotReachable)
    {
        //关闭网络检测定时器
        [self destoryNetWorkStartTesting];
        //开始重连
        [self reConnectServer];
    }
}

#pragma mark --------------------------------------------------- socket 取消网络检测
- (void)destoryNetWorkStartTesting{
    WEAKSELF
    dispatch_main_async_safe(^{
        if(weakSelf.netWorkTestingTimer) {
            [weakSelf.netWorkTestingTimer invalidate];
            weakSelf.netWorkTestingTimer = nil;
        }
    });
}

#pragma mark --------------------------------------------------- socket 取消心跳
- (void)destoryHeartBeat{
    WEAKSELF
    dispatch_main_async_safe(^{
        if(weakSelf.heartBeatTimer)
        {
            [weakSelf.heartBeatTimer invalidate];
            weakSelf.heartBeatTimer = nil;
        }
    });
}

#pragma mark --------------------------------------------------- socket 关闭长连接
- (void)SRWebSocketClose{
    
//    self.reConnectTime = 0;
    self.isActivelyClose = YES;
    self.isConnect = NO;
    self.connectType = WebSocketDefault;
    if(self.webSocket) {
        [self.webSocket close];
        _webSocket = nil;
    }
    //关闭心跳定时器
    [self destoryHeartBeat];
    //关闭网络检测定时器
    [self destoryNetWorkStartTesting];
    
//    [SVProgressHUD showWithStatus:@"主动关闭与拍价服务器的连接"];
//    [SVProgressHUD dismissWithDelay:1];
}

#pragma mark --------------------------------------------------- socket 发送数据给服务器
- (void)sendDataToServer:(id)data{
    
    [self.sendDataArray addObject:data];
    //[_webSocket sendString:data error:NULL];
    //没有网络
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
        //开启网络检测定时器
        [self noNetWorkStartTestingTimer];
    }
    else  {//有网络
        
        if(self.webSocket != nil)
        {
            // 只有长连接OPEN开启状态才能调 send 方法，不然会Crash
            if(self.webSocket.readyState == SR_OPEN) {
                [self.webSocket send:data];
                
            }  else if (self.webSocket.readyState == SR_CONNECTING) {
                NSLog(@"正在连接中，重连后会去自动同步数据");
                
            } else if (self.webSocket.readyState == SR_CLOSING || self.webSocket.readyState == SR_CLOSED) {//断开连接
                //调用 reConnectServer 方法重连,连接成功后 继续发送数据
                [self reConnectServer];
            }
            
        } else {
            
            [self connectServer]; //连接服务器
        }
    }
}


@end
